using System;
using System.Collections.Generic;
using System.Text;
using IWS.Lib.SingleSignOn.ServiceResponses;


namespace IWS.Lib.SingleSignOn
{
	/// <summary>
	/// Web service role provider. 
	/// </summary>
	public class WebServiceRoleProvider : System.Web.Security.RoleProvider
	{
		private string SessionKey;
		private object objLock;
		private bool EstablishingSession;
		private bool SessionEstablished; //not really used. Thought about using it to refresh the session key on an interval. meh... 
		private string[] GetStringArray(object[] array)
		{
			if (array != null)
			{
				string[] list = new string[array.Length];
				for (int ix = 0; ix < array.Length; ix++)
				{
					list[ix] = array[ix].ToString();
				}
				return list;
			}
			else
			{
				return null;
			}
		}

		/// <summary>
		/// Create an instance of the web service role provider
		/// </summary>
		public WebServiceRoleProvider()
		{
			this.SessionKey = String.Empty;
			objLock = new object();
			EstablishingSession = false;
			SessionEstablished = false;
		}

		/// <summary>
		/// Initialize the provider. 
		/// </summary>
		/// <remarks>Part of the initialization process includes establishing a session with the remote provider for security.</remarks>
		/// <param name="name"></param>
		/// <param name="config"></param>
		public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
		{
			base.Initialize(name, config);

			this.EstablishSession();
		}

		// return true if session was succesfully established.  Throws exception if anything goes wrong.
		public void EstablishSession()
		{
			lock (this.objLock) //create lock to only allow one thread in this function at a time. 
			{
				if (!EstablishingSession) //double check (probably useless)
				{
					this.PerformEstablishSession();
				}
			}
		}

		public void ExpireSession()
		{
			this.LogOut();
		}

		private void PerformEstablishSession()
		{
			EstablishingSession = true;
			bool success = this.Login(Properties.Settings.Default.ServiceUsername, Properties.Settings.Default.ServicePassword);
			this.SessionEstablished = success;

			if (!success)
			{
				throw new Exceptions.ServiceException("Invalid service login. Cannot complete membership request.");
			}
			EstablishingSession = false;
		}

		private bool Login(string username, string password)
		{
			bool result = false;
			MembershipWebService.MembershipService svc = new IWS.Lib.SingleSignOn.MembershipWebService.MembershipService();
			ServiceResponse resp = svc.AuthenticateSession(username, password);
			if (resp.Result == ServiceResponse.eResult.Success || resp.Result == ServiceResponse.eResult.InvalidLogin)
			{
				if (resp.Result == ServiceResponse.eResult.Success && resp.Data != null)
				{
					this.SessionKey = resp.Data.ToString();
					result = true;
				}
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
			return result;
		}

		private void LogOut()
		{
			MembershipWebService.MembershipService svc = new IWS.Lib.SingleSignOn.MembershipWebService.MembershipService();
			ServiceResponse resp = svc.ExpireSession(this.SessionKey);
			if (resp.Result != ServiceResponse.eResult.Success)
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
			this.SessionEstablished = false;
			this.SessionKey = String.Empty;
		}


		public override void AddUsersToRoles(string[] usernames, string[] roleNames)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.AddUsersToRoles(this.SessionKey, usernames, roleNames);
			if (resp.Result != ServiceResponse.eResult.Success)
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string ApplicationName
		{
			get
			{
				RoleWebService.RoleService svc = new RoleWebService.RoleService();
				ServiceResponse resp = svc.GetApplicationName(this.SessionKey);
				if (resp.Result == ServiceResponse.eResult.Success)
				{
					if (resp.Data != null)
						return resp.Data.ToString();
					else
						throw new Exceptions.ServiceException("Response contains no data.");
				}
				else
					throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
			set
			{
				RoleWebService.RoleService svc = new RoleWebService.RoleService();
				ServiceResponse resp = svc.SetApplicationName(this.SessionKey, value);
				if (resp.Result != ServiceResponse.eResult.Success)
					throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
			}
		}

		public override void CreateRole(string roleName)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.CreateRole(this.SessionKey, roleName);
			if (resp.Result != ServiceResponse.eResult.Success)
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.DeleteRole(this.SessionKey, roleName, throwOnPopulatedRole);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new Exceptions.ServiceException("Response contains no data.");
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string[] FindUsersInRole(string roleName, string usernameToMatch)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ArrayServiceResponse resp = svc.FindUsersInRole(this.SessionKey, roleName, usernameToMatch);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				return GetStringArray(resp.Data);
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string[] GetAllRoles()
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ArrayServiceResponse resp = svc.GetAllRoles(this.SessionKey);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				return GetStringArray(resp.Data);
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string[] GetRolesForUser(string username)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ArrayServiceResponse resp = svc.GetRolesForUser(this.SessionKey, username);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				return GetStringArray(resp.Data);
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override string[] GetUsersInRole(string roleName)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ArrayServiceResponse resp = svc.GetUsersInRole(this.SessionKey, roleName);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				return GetStringArray(resp.Data);
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool IsUserInRole(string username, string roleName)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.IsUserInRole(this.SessionKey, username, roleName);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new Exceptions.ServiceException("Response contains no data.");
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.RemoveUsersFromRoles(this.SessionKey, usernames, roleNames);
			if (resp.Result != ServiceResponse.eResult.Success)
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}

		public override bool RoleExists(string roleName)
		{
			RoleWebService.RoleService svc = new RoleWebService.RoleService();
			ServiceResponse resp = svc.RoleExists(this.SessionKey, roleName);
			if (resp.Result == ServiceResponse.eResult.Success)
			{
				if (resp.Data != null)
					return (bool)resp.Data;
				else
					throw new Exceptions.ServiceException("Response contains no data.");
			}
			else
				throw new Exceptions.ServiceException(resp.Result.ToString() + ": " + resp.Message);
		}
	}
}
